<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
    />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Convex Objects Breaking</title>
    <link rel="stylesheet" href="/css/examples.css?ver=1.0.0" />
    <script src="/js/examples.js?ver=1.1.1"></script>
    <script src="/lib/three.min.js"></script>
    <script src="/lib/ConvexHull.js"></script>
    <script src="/lib/ConvexGeometry.js"></script>
    <script src="/lib/OrbitControls.js"></script>
    <script src="/lib/enable3d/enable3d.ammoPhysics.0.22.0.min.js"></script>
  </head>

  <body>
    <script>
      const { AmmoPhysics, PhysicsLoader } = ENABLE3D

      const MainScene = () => {
        // scene
        const scene = new THREE.Scene()
        scene.background = new THREE.Color(0xf0f0f0)

        // camera
        const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000)
        camera.position.set(10, 10, 20)

        // renderer
        const renderer = new THREE.WebGLRenderer()
        renderer.setSize(window.innerWidth, window.innerHeight)
        document.body.appendChild(renderer.domElement)

        // dpr
        const DPR = window.devicePixelRatio
        renderer.setPixelRatio(Math.min(2, DPR))

        // orbit controls
        const controls = new THREE.OrbitControls(camera, renderer.domElement)

        // light
        scene.add(new THREE.HemisphereLight(0xffffbb, 0x080820, 1))
        scene.add(new THREE.AmbientLight(0x666666))
        const light = new THREE.DirectionalLight(0xdfebff, 1)
        light.position.set(50, 200, 100)
        light.position.multiplyScalar(1.3)

        // physics
        const physics = new AmmoPhysics(scene, { maxSubSteps: 4, fixedTimeStep: 1 / 120 })
        physics.debug.enable(true)

        // elements
        addHouse(physics)
        initCanon(physics, camera)

        // clock
        const clock = new THREE.Clock()

        // loop
        const animate = () => {
          physics.update(clock.getDelta() * 1000)
          physics.updateDebugger()
          renderer.render(scene, camera)

          requestAnimationFrame(animate)
        }
        requestAnimationFrame(animate)
      }

      const addHouse = physics => {
        // extract the object factory from physics
        // the factory will make/add object without physics
        const { factory } = physics

        const config = {
          depth: 0.4,
          breakable: true,
          fractureImpulse: 5,
          collisionFlags: 3
        }

        // front
        physics.add.box({ y: 3, x: 2, z: 4, width: 4, height: 2, ...config })
        physics.add.box({ y: 1, x: 2, z: 4, width: 4, height: 2, ...config })
        physics.add.box({ y: 1, x: -2, z: 4, width: 4, height: 2, ...config })
        physics.add.box({ y: 3, x: -2, z: 4, width: 4, height: 2, ...config })

        // back
        physics.add.box({ y: 1, x: -2, z: 0, width: 4, height: 2, ...config })
        physics.add.box({ y: 3, x: -2, z: 0, width: 4, height: 2, ...config })
        physics.add.box({ y: 1, x: 2, z: 0, width: 4, height: 2, ...config })
        physics.add.box({ y: 3, x: 2, z: 0, width: 4, height: 2, ...config })

        // left and right
        physics.add.box({ ...config, y: 2, x: -4, z: 2, depth: 4, height: 4, width: 1 })
        physics.add.box({ ...config, y: 2, x: 4, z: 2, depth: 4, height: 4, width: 1 })

        // roof
        let r1 = factory.add.box({ y: 4.75, x: 0, z: 0.5, width: 8, height: 4, ...config })
        let r2 = factory.add.box({ y: 4.75, x: 0, z: 3.5, width: 8, height: 4, ...config })
        r1.rotateX(Math.PI / 4)
        r2.rotateX(-Math.PI / 4)
        physics.add.existing(r1, { collisionFlags: 3, breakable: true })
        physics.add.existing(r2, { collisionFlags: 3, breakable: true })
      }

      const initCanon = (physics, camera) => {
        const raycaster = new THREE.Raycaster()
        const force = 30

        window.addEventListener('pointerdown', event => {
          // calculate mouse position in normalized device coordinates
          // (-1 to +1) for both components
          const x = (event.clientX / window.innerWidth) * 2 - 1
          const y = -(event.clientY / window.innerHeight) * 2 + 1
          raycaster.setFromCamera({ x, y }, camera)

          const pos = new THREE.Vector3()

          pos.copy(raycaster.ray.direction)
          pos.add(raycaster.ray.origin)

          const sphere = physics.add.sphere(
            {
              radius: 0.15,
              x: pos.x,
              y: pos.y,
              z: pos.z,
              mass: 20,
              bufferGeometry: true
            },
            { phong: { color: 0x202020 } }
          )
          sphere.body.setBounciness(0.2)

          pos.copy(raycaster.ray.direction)
          pos.multiplyScalar(24)

          sphere.body.applyForce(pos.x * force, pos.y * force, pos.z * force)
        })
      }

      PhysicsLoader('/lib/ammo/kripken', () => MainScene())

      console.log(`three.js version "${THREE.REVISION}"`)
    </script>
  </body>
</html>
